<?php

class Ext_Model_User extends Ext_Db_Table
{

    protected $_rowClass = "Ext_Model_UserRow";

    protected $_name = 'sys_user';

    protected $_primary = 'user_id';

    protected $_sequence = 'sys_user_seq';

    protected $_useEndDate = true;

    // Salt is not user any more.
    public function getAuthenticatedUser( $user, $pass, $ownerId = null )
    {
        error_log("el usuario es ". $user );
        if ( empty( $user ) ) {
            return null;
        }
        $select = $this->select()
        ->where( 'end_date is null and locked = \'F\'' )
        ->where( 'username = ?', $user );
		
        // if an owner was specified add to where clause
        if ( $ownerId ) {
            $select->where( 'owner_id = ?', $ownerId );
        }

        $result = $this->fetchRow( $select );
		
        if ( ! empty( $result ) ){
        	if( empty( $pass)){
        		return $result;
        	}
        	if( crypt( $pass, $result->password ) == $result->password ) {
        		return $result;	
        	}
        }
        return null;
    }

    public function changePassword( $user, $pass )
    {
        $user = $this->getUserByName( $user );
        if ( empty( $user ) ) {
            return false;
        }
        $user->changePassword( $pass );
        $user->save();
        return true;
    }

    public function getCredential($userId, $expire = null)
    {
        $encrypt = new Zend_Filter_Encrypt(
            array(
                'key' => Zend_Registry::get('config')->user->credential->passphrase,
                'vector' => Zend_Registry::get('config')->user->credential->vector,
                'salt' => Zend_Registry::get('config')->user->credential->salt
            )
        );
        $obj = new stdClass();
        $obj->userId = $userId;
        $obj->timestamp = time();
        $obj->expireTime =  ( empty( $expire )) ? Zend_Registry::get('config')->user->credential->expire : $expire;
        $obj->token = sha1( uniqid(mt_rand(), true) . time() );
        $serializedObject = serialize( $obj );
        $credential = base64_encode( $encrypt->filter( $serializedObject )) ;
        return $credential;
    }

    public function checkCredential( $userId, $credential )
    {
        $decrypt = new Zend_Filter_Decrypt(
            array(
                'key' => Zend_Registry::get('config')->user->credential->passphrase,
                'vector' => Zend_Registry::get('config')->user->credential->vector,
                'salt' => Zend_Registry::get('config')->user->credential->salt
            )
        );

        $result = $decrypt->filter( base64_decode( $credential ));
        $obj = unserialize( $result );
        if( !isset( $obj->userId ) ) {
            throw new Ext_Exception('Your credential is Broken 1');
        }
        if( $obj->userId == $userId ) {
            $diff =  time() - $obj->timestamp;
            /**
             * @todo BORRAR
             */
            return true;
            if( $diff > $obj->expireTime ) {
                throw new Ext_Exception('Expired',101 );
            } else {
                return true;
            }
        } else {
            throw new Ext_Exception('Your credential is Broken 2');
        }
    }

    public function getUserId( $user )
    {
        $result = $this->getUserByName( $user );
        if ( empty( $result ) ) {
            return null;
        }
        return $result->user_id;
    }

    public function getUserByName( $user )
    {
        $select = $this->select()->where( 'end_date is null' )->where( 'username = ?', $user );
        return $this->fetchRow( $select );
    }

    // returns object with all properties of user: user data,
    // profile, roles, acls, etc.
    public function getUser( $userId )
    {
        // safety check
        if ( ! is_numeric( $userId ) ) {
            return null;
        }
        // load record
        // TODO: verificar que anda si no encuentra el usuario
        return $this->find( $userId )->current();
    }

    public function addUser( $user, $pass )
    {
        $ret = $this->getUserId( $user );
        if ( $ret !== null ) {
            return $ret;
        }
        $id = $this->insert( array(
            'username' => $user,
            'password' => crypt( $pass, "$1$" . substr( uniqid(), 0, 7 ) . "$" ),
            'creation_date' => new Zend_Db_Expr( 'sysdate' ),
            'locked' => 'F',
            'end_date' => NULL
            ) );
        /**
         * Si la tabla tiene una secuencia se tiene que devolver Id de la siguiente forma
         */
        if ( $id === true ) {
            $id = $this->getAdapter()->lastInsertId( $this->_sequence );
        }
        return $id;
    }

    public function delUser( $user )
    {
        $user = $this->getUserByName( $user );
        if ( empty( $user ) ) {
            return false;
        }
        $user->end_date = new Ext_Db_Date( Ext_Db_Date::NOW );
        $user->save();
        return true;
    }

    public function getUserComplete( $userId )
    {
        $data = $this->find( $userId )->current();
        if( ! count( $data )) {
            return false;
        }
        $userInfo['basic'] = $data->toArray();
        unset( $userInfo['basic']['password'] );

        $rowset = $this->getAdapter()->fetchAll( $this->getAdapter()->select()
            ->from( array( 'us' => 'sys_user' ), array('') )
            ->join( array ( 'usp' => 'sys_user_property' ), 'usp.user_id = us.user_id', array('property', 'value'))
            ->where( 'us.user_id = ?', $userId )) ;
        if( count( $rowset)){
            $userInfo['properties'] = $rowset;
        }

        $rowset = $this->getAdapter()->fetchAll( $this->getAdapter()->select()
            ->from( array( 'us' => 'sys_user' ), array('') )
            ->join( array ( 'usr' => 'sys_user_role' ), 'usr.user_id = us.user_id', array('role_id'))
            ->where( 'us.user_id = ?', $userId )) ;
        if( count( $rowset )){
            $userInfo['roles'] = $rowset;
        }
        return $userInfo;
    }

    public function getAcl( $user )
    {
        $acl = new Zend_Acl( );
        $resourceDb = new Ext_Model_Resource( $user->getTable()->getAdapter() );
        $resources = $resourceDb->fetchAll();
        foreach ( $resources as $resource ) {
            $acl->add( new Zend_Acl_Resource( $resource->name ) );
        }
        $userRoles = $user->findManyToManyRowset( 'Ext_Model_Role', 'Ext_Model_UserRole' );
        $userRoleIds = array();
        foreach ( $userRoles as $role ) {

            $acl->addRole( new Zend_Acl_Role( $role->role_id ), $role->parent_role_id );
            $select = "select a.*,b.name
                   from sys_acl_rule a, sys_resource b
                   where a.resource_id = b.resource_id
                   and a.role_id = $role->role_id
                   order by priority";
            $permsRS = $user->getTable()->getAdapter()->fetchAll( $select );
            foreach ( $permsRS as $perm ) {
                if ( strtoupper( $perm[ 'permission' ] ) === "ALLOW" ) {
                    $acl->allow( $role->role_id, $perm[ 'name' ], $perm[ 'operation' ] );
                } else {
                    $acl->deny( $role->role_id, $perm[ 'name' ], $perm[ 'operation' ] );
                }
            }
            $userRoleIds[] = $role->role_id;
        }
        $acl->addRole( new Zend_Acl_Role( $user->username ), $userRoleIds );
        //        return $acl->;

    }
}






class Ext_Model_UserRow extends Ext_Db_Table_Row
{

    /**
     * must be implemented to use distinct owners if the model is more complex.
     *
     * @return integer
     */
    protected function getOwnerId()
    {
        /**
         * WTF!!?
         */
        return 1;
    }

    /**
     * Allows pre-insert logic to be applied to row.
     * Subclasses may override this method.
     *
     * @return void
     */
    protected function _insert()
    {
        $this->creation_date = new Ext_Db_Date( Ext_Db_Date::NOW );
        if ( empty( $this->owner_id ) ) {
            $this->owner_id = $this->getOwnerId();
        }
        if ( empty( $this->password ) ) {
            $this->password = 'X';
        }

        if ( empty( $this->locked ) ) {
            $this->locked = 'F';
        }
    }

    public function  __set($columnName, $value) {
        if ( ! strcasecmp( $columnName, "passowrd" ) ) {
            return;
        }
        try {
            return parent::__set( $columnName, $value );
        } catch( Zend_Db_Table_Row_Exception $e ) {
        }
        if ( empty( $this->user_id ) ) {
            throw new Exception( "invalid userId" );
        }
        $db = new Ext_Model_UserProperty( $this->getTable()->getAdapter() );
        $db->setUserProp( $this->user_id, $columnName, $value );
    }


    public function __get( $columnName )
    {
        if ( ! strcasecmp( $columnName, "passowrd" ) ) {
            return "";
        }
        try {
            return parent::__get( $columnName );
        } catch( Zend_Db_Table_Row_Exception $e ) {
        }
        if ( empty( $this->user_id ) ) {
            throw new Exception( "invalid userId" );
        }
        $db = new Ext_Model_UserProperty( $this->getTable()->getAdapter() );
        $property = $db->find( $this->user_id, $columnName )->current();
        if ( empty( $property ) ) {
            return "";
        }
        return $property->value;
    }

    public function changePassword( $pass )
    {
        if ( empty( $this->password ) ) {
            $this->password = crypt( $pass, "$1$" . substr( uniqid(), 0, 7 ) . "$" );
        } else {
            $this->password = crypt( $pass, $this->password );
        }
        return true;
    }

    private $roles = null;

    public function haveRole( $roleId )
    {
        if ( $this->roles === null ) {
            $roles = $this->findExt_Model_UserRole();
            $this->roles = array();
            foreach ( $roles as $role ) {
                $this->roles[ $role->role_id ] = $role;
            }
        }
        return array_key_exists( $roleId, $this->roles );
    }
}

